﻿using IoTClient.Enums;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Serialization;

/******************************************************扩展************************************************************/

namespace IoTClient
{
    public partial class SerialPortBase
    {
        /// <summary>
        /// 警告日志委托
        /// 为了可用性，会对异常网络进行重试。此类日志通过委托接口给出去。
        /// </summary>
        [XmlIgnore]
        [Browsable(false)]
        public LoggerDelegate Loger { get; set; }

        /// <summary>
        /// 报警将激发的事件
        /// </summary>
        [Browsable(false)]
        [XmlIgnore]
        public Action<Variable, AlarmEventArgs> Alarming { get; set; }

        /// <summary>
        /// 是否采用Auto方式
        /// </summary>
        [Browsable(false)]
        [XmlIgnore]
        public bool IsAuto { get; set; } = true;

        ///// <summary>
        ///// 异常错误将激发的事件
        ///// </summary>
        //[XmlIgnore] public Action<object, Exception> Erroring { get; set; }
        /// <summary>
        /// 设备名
        /// </summary>
        [JsonProperty("设备名")]
        [DisplayName("设备名")]
        public string Name { get; set; } = "串口设备";

        /// <summary>
        /// 是否启用
        /// </summary>
        [JsonProperty("是否启用"), DisplayName("是否启用")] public bool IsActive { get; set; } = true;

        /// <summary>
        ///
        /// </summary>
        [JsonProperty("字节格式"), DisplayName("字节格式")] public EndianFormat Format { get; set; }

        /// <summary>
        /// 是否是第一次连接,用于判断重连是否等待
        /// </summary>
        [XmlIgnore, Browsable(false)] public bool IsFirstConnect { get; set; } = true;

        /// <summary>
        /// 统计重连次数
        /// </summary>
        [XmlIgnore, Browsable(false)] public int ReconnectionCount { get; set; } = 0;

        /// <summary>
        /// 读取一次全部变量花的时间
        /// </summary>
        [XmlIgnore, Browsable(false)] public double? CycleTime { get; set; } = 0;

        /// <summary>
        /// 超时时间
        /// </summary>
        [JsonProperty("超时时间毫秒"), DisplayName("超时时间")]
        public int Timeout { get; set; } = 1500;

        /// <summary>
        /// 通过判断socket的状态,确定当前是否是连接的
        /// </summary>
        [XmlIgnore, Browsable(false)]
        public bool Connected { get; set; } = false;

        /// <summary>
        /// 变量描述
        /// </summary>
        [JsonProperty("设备描述"), DisplayName("设备描述")] public string Description { get; set; } = $"描述这是一个什么样的的设备........";

        /// <summary>
        /// 所有的变量
        /// </summary>
        [XmlArray("变量集合")]
        [XmlArrayItem("变量"), DisplayName("所有的变量集合")]
        public List<ModbusVariable> AllVarableList { get; set; } = new List<ModbusVariable>() { };

        /// <summary>
        /// 所有的变量地址,数据类型
        /// </summary>
        [XmlIgnore, Browsable(false)]
        public Dictionary<string, DataTypeEnum> VarableAddressList = new Dictionary<string, DataTypeEnum>();

        /// <summary>
        /// 所有变量的字典集合
        /// </summary>
        [XmlIgnore, Browsable(false)]
        public Dictionary<string, ModbusVariable> AllVarableDictionary { get; set; } = new Dictionary<string, ModbusVariable>();

        /// <summary>
        /// 分批缓冲区大小;没必要不要改,默认就好
        /// </summary>
        protected const int BufferSize = 4096;

        /// <summary>
        /// 用于取消线程
        /// </summary>
        [XmlIgnore, Browsable(false)] public CancellationTokenSource Cts { get; set; } = new CancellationTokenSource();

        /// <summary>
        /// 端口名
        /// </summary>
        [JsonProperty("端口名"), DisplayName("端口名")] public string PortName { get; set; } = "COM2";

        /// <summary>
        /// 波特率
        /// </summary>
        [JsonProperty("波特率"), DisplayName("波特率")] public int BaudRate { get; set; } = 9600;

        /// <summary>
        /// 校验位
        /// </summary>
        [JsonProperty("校验位"), DisplayName("校验位")] public Parity Parity { get; set; } = Parity.None;

        /// <summary>
        /// 数据位
        /// </summary>
        [JsonProperty("数据位"), DisplayName("数据位")] public int DataBits { get; set; } = 8;

        /// <summary>
        /// 停止位
        /// </summary>
        [JsonProperty("停止位"), DisplayName("停止位")] public StopBits StopBits { get; set; } = System.IO.Ports.StopBits.One;

        /// <summary>
        /// Encoding格式
        /// </summary>
        [JsonProperty("Encoding格式"), DisplayName("Encoding格式")] public EncodingEnum EncodingType { get; set; } = EncodingEnum.ASCII;

        /// <summary>
        /// 是否为plc地址 默认false
        /// </summary>
        [JsonProperty("是否为plc地址"), DisplayName("是否为plc地址")] public bool plcAddresses { get; set; } = false;

        /// <summary>
        /// 开一个线程,不停的去读取这个设备
        /// </summary>
        /// <returns></returns>
        public virtual Result Start()
        {
            Result result = new Result();
            //todu 验证地址是否符合要求................
            try
            {
                AllVarableDictionary = AllVarableList.ToDictionary(x => (Name + "_" + x.Address).ToUpper().Trim(), x => x);
                AllVarableList.ForEach(x => x.AlarmEnable = x.HHighAlarmEnable & x.HighAlarmEnable & x.LLowAlarmEnable & x.LowAlarmEnable);
                Task.Run(() =>
                {
                    while (!Cts.IsCancellationRequested)
                    {
                        if (Connected)
                        {
                            //   var x=    Read("1");
                            //    var xx= ReadFloat("1");
                            var res = result;
                            if (res.IsSucceed)
                            {
                                CycleTime = res.TimeConsuming;
                            }
                            else
                            {
                                Loger?.Invoke($"{this.Name}:BatchRead失败:{res.Err}", res.Exception);
                            }
                        }
                        else
                        {
                            if (IsFirstConnect)
                            {
                                var res = Open2();
                                Loger?.Invoke($"{this.Name}:第一次连接{(res.IsSucceed ? "成功" : "失败")};", res.Exception);
                                Connected = res.IsSucceed;
                            }
                            else
                            {
                                Loger?.Invoke($"重连中.....一共重连了{ReconnectionCount}次");
                                Thread.Sleep(Timeout);
                                var res = Open2();
                                Connected = res.IsSucceed;
                                Loger?.Invoke($"{this.Name}:第{ReconnectionCount}次重连{(res.IsSucceed ? "成功" : "失败")};异常消息:{res.Err}", res.Exception);
                                if (res.IsSucceed)
                                {
                                    ReconnectionCount = 0;
                                    Loger?.Invoke($"{this.Name}:第{ReconnectionCount}次重连成功;");
                                }
                                else
                                {
                                    ReconnectionCount++;
                                    Loger?.Invoke($"{this.Name}:第{ReconnectionCount}次重连失败;异常消息:{res.Err}", res.Exception);
                                }
                            }
                            IsFirstConnect = false;
                        }
                    }
                }, this.Cts.Token);
            }
            catch (Exception ex)
            {
                Loger?.Invoke($"{this.Name}初始化字典集合或者开启线程失败:{ex.Message}", ex);
                result.IsSucceed = false;
                result.Err = $"{this.Name}初始化字典集合或者开启线程失败";
                result.Exception = ex;
                return result;
            }
            result.IsSucceed = true;
            result.Err = $"{this.Name}:启动成功";
            return result;
        }

        #region Override

        /// <summary>
        /// 打开连接
        /// </summary>
        /// <returns></returns>
        public Result Open2()
        {
            isAutoOpen = false;
            return Connect2();
        }

        /// <summary>
        /// 连接
        /// </summary>
        /// <returns></returns>
        protected Result Connect2()
        {
            var result = new Result();
            if (serialPort == null) serialPort = new SerialPort();
            serialPort.PortName = PortName;
            serialPort.BaudRate = BaudRate;
            serialPort.DataBits = DataBits;
            serialPort.StopBits = StopBits;
            serialPort.Encoding = GetEncoding(EncodingType);
            serialPort.Parity = Parity;
            serialPort.ReadTimeout = Timeout;
            serialPort.WriteTimeout = Timeout;
            plcAddresses = plcAddresses;
            serialPort?.Close();
            try
            {
                serialPort.Open();
            }
            catch (Exception ex)
            {
                if (serialPort?.IsOpen ?? false) serialPort?.Close();
                result.IsSucceed = false;
                result.Err = ex.Message;
                result.ErrCode = 408;
                result.Exception = ex;
            }
            return result.EndTime();
        }

        private Encoding GetEncoding(EncodingEnum type)
        {
            switch (type)
            {
                case EncodingEnum.UTF8:
                    return Encoding.UTF8;

                case EncodingEnum.Unicode:
                    return Encoding.Unicode;

                case EncodingEnum.BigEndianUnicode:
                    return Encoding.BigEndianUnicode;

                case EncodingEnum.ASCII:
                    return Encoding.ASCII;

                case EncodingEnum.Default:
                    return Encoding.Default;
            }
            return Encoding.UTF8;
        }

        #endregion Override
    }
}